/*
 * file:  program.h (contains declarations of Program, StmtList, Stmt, Expr)
 * Author: Jeremy Johnson 
 * Date: 2/05/07
 *
 * Description:
 */
#include <iostream>
#include <string>
#include <map>
#include <list>
#include <vector>

#define VALUE 0
#define LIST  1
#define EMPTY_LIST  2
#define PROCEDURE	3

#define T_EXPR 	0
#define T_IDENT	1
#define T_PROC	2
#define T_FUNC	3
#define T_LIST	4

#define DYNAMIC 1
#define STATIC 	2

using namespace std;


// forward declarations 
// StmtList used by IfStmt and WhileStmt which are Stmt
// Proc which contains StmtList used in Expr, Stmt, StmtList 
class StmtList;
class Proc;

class Element;
class List;
class Heap;

/////////////////////////////
class Element
{
	public:
		Element(){};
		~Element(){};
		Element(int _value, int _dataType);
		Element(string _identifier, int _dataType);
		
		void print(Heap *heap);
		void printList(Heap *heap, int position);
		
		Element& operator=(const Element& elm);
		void update(int _value, int _dataType);
		
		int value;
		string identifier;
		int dataType;
};

class HeapCell
{
	public:
		HeapCell(int _cdr);
		~HeapCell(){};
		void print();

	//private:
		bool mark;//used for mark and sweep
		bool isPtr;//value stored is a ptr or an integer?
		bool isEmptyList;//is the value stored stands for an empty list?
		int car;//stored value, may be an integer or a pointer to another list
		int cdr;//rest of the list
};

class Heap
{
	public:
		Heap(){};
		Heap(int size,map<string,Element> *_nameTable);
		~Heap();
		void print();
		
		bool isAvailable();		
		void updateAvailableCell();
		
		void markAndSweep();
		void mark(int ptr);
		void sweep();
		void unmark();
		
		int  putValue(Element elm, int _cdr);
		int  putEmptyList();
		
		vector<HeapCell> cells;
		int heapSize;
		int available;
		
		map<string,Element> *nameTable;
		
		map<int,int> tempNameTable;
		int tempNameTablePtr;
};
////////////////////////////////////////////////////////////////////////////
class Expr
{
public:
	Expr() {};
	virtual ~Expr() {};  
	virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping)=0;  
	virtual Element apply(map<string,Element> &NT, map<string,Proc*> &FT, Heap *heap, list<Expr*> *EL){return Element(1,VALUE);};
	
	virtual int type(){return T_EXPR;};

private:
};
////////////////////////////////////////////////////////////////////////////
//list funtions
class Cons:public Expr
{
	public:
		Cons(Expr * _expr = NULL, Expr * _list = NULL){expr = _expr;lst = _list;};
		virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
	
	private:
		Expr *expr,*lst;
};

class Concatenate:public Expr
{
	public:
		Concatenate(Expr * _l1 = NULL, Expr * _l2 = NULL){l1=_l1;l2=_l2;};
		virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
	
	private:
		Expr *l1,*l2;
};

class Cdr:public Expr
{
	public:
		Cdr(Expr * _expr){expr = _expr;};
		virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
	
	private:
		Expr *expr;
};

class Car:public Expr
{
	public:
		Car(Expr * _exp = NULL){expr = _exp;};
		virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
	
	private:
		Expr *expr;
};

class Nullp:public Expr
{
	public:
		Nullp(Expr * _exp){lst = _exp;};
		virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
	
	private:
		Expr *lst;
};
class Intp:public Expr
{
	public:
		Intp(Expr * _exp){exp = _exp;};
		virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
	
	private:
		Expr *exp;
};
class Listp:public Expr
{
	public:
		Listp(Expr * _exp){exp = _exp;};
		virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
	
	private:
		Expr *exp;
};

/////////////////////////////
class List:public Expr
{
	public:
		List(){};
		~List(){};
		virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
		virtual int type(){return T_LIST;};

		void insertSequence(Expr *_sequence){sequence = _sequence;};
		
	//private:
		Expr *sequence;
};
/////////////////////////////
class Number : public Expr
{
public:
	Number(int value = 0);
	virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
	int value(){return value_;};
private:
	int value_;
};


class Ident : public Expr
{
public:
	Ident(string name = "");
	virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
private:
	string name_;
};

class Times : public Expr
{
public:
	Times(Expr * op1 = NULL, Expr * op2 = NULL);
	virtual ~Times() {delete op1_; delete op2_;};
	virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
private:
	Expr* op1_;
	Expr* op2_;
};

class Plus : public Expr
{
public:
	Plus(Expr* op1 = NULL, Expr* op2 = NULL);
	virtual ~Plus() {delete op1_; delete op2_;};
	virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
private:
	Expr* op1_;
	Expr* op2_;
};

class Minus : public Expr
{
public:
	Minus(Expr* op1 = NULL, Expr* op2 = NULL);
	virtual ~Minus() {delete op1_; delete op2_;};
	virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
private:
	Expr* op1_;
	Expr* op2_;
};

class FunCall : public Expr
{
public:
	FunCall(Expr *_exp, list<Expr*> *AL);
	virtual ~FunCall(){ delete AL_; };
	virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
	
	virtual int type(){return T_FUNC;};
private:
	string name_;
	list<Expr*> *AL_;
	
	Expr *exp;
	int type_;
};

class Proc : public Expr
{
public:
	Proc(list<string> *PL, StmtList *SL);
	virtual ~Proc() {delete SL_; delete PL_; };  
	Element apply(map<string,Element> &NT, map<string,Proc*> &FT, Heap *heap, list<Expr*> *EL, map<string,map<string,Element> > &FNT, int scoping, string funcName);
	virtual Element eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);
	
	virtual int type(){return T_PROC;};
	
private:
	StmtList *SL_;
	list<string> *PL_;
	int NumParam_;
};

class Stmt 
{
public:
	Stmt() {};
	virtual ~Stmt() {};  
	virtual void eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping) const = 0;  

private:
};


class AssignStmt: public Stmt
{
public:
	AssignStmt(string name="", Expr *E=NULL);
	~AssignStmt() {delete E_;}; 
	void eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping) const;
private:
	string name_;
	Expr* E_;
};

class DefineStmt : public Stmt
{ 
public:
	DefineStmt(string name="", Proc *P=NULL);
	virtual ~DefineStmt();  
	virtual void eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping) const;  
private:
	string name_;
	Proc* P_;
};


class IfStmt: public Stmt
{
public:
	IfStmt(Expr *E,StmtList *S1, StmtList *S2);
	~IfStmt();
	void eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping) const;
private:
	Expr* E_;
	StmtList *S1_;
	StmtList *S2_;
};

class WhileStmt: public Stmt
{
public:
	WhileStmt(Expr *E,StmtList *S);
    ~WhileStmt();
	void eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping) const;
private:
	Expr* E_;
	StmtList *S_;
};


class StmtList 
{
public:
	StmtList() {};
	void eval(map<string,Element> &NT, map<string,Proc*> &FT, map<string,map<string,Element> > &FNT, Heap *heap, int scoping);  
	void insert(Stmt *T);  

private:
	list<Stmt*> SL_;
};

class Program 
{
public:
	Program(StmtList *SL, int _memSize, int _scoping);
	~Program() {delete SL_; };  
	void dump();
	void eval();
	
	void buildHeap( map<string,Element> *nameTable){heap = new Heap(memSize,nameTable);};
	void printHeap(){heap->print();};

private:
	StmtList *SL_;
	map<string,Element> NameTable_;
	map<string,map<string,Element> > ProcNameTables;
	map<string,Proc*> FunctionTable_;
	
	Heap	*heap;
	int memSize;
	
	int scoping;
};
